.TITLE DBDRV .IDENT /16.12/ ; ; Copyright (c) 1995-1999 by Mentec, Inc., U.S.A. ; All rights reserved ; ; ; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED ; OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE. ; ; P. J. BEZEREDI 19-SEP-79 ; ; MODIFIED FOR M-PLUS V2.0 BY: ; ; R. T. PERRON ; P. J. BEZEREDI ; T. LEKAS ; ; MODIFIED BY: ; ; P. J. CARR 9-JUN-82 16.01 ; ; PJC052 -- CORRECT SEEK OPTIMIZATION. ; ; P. J. CARR 27-AUG-82 16.02 ; ; PJC063 -- COUNT EACH DIFFERENT OFFSET AS 1 RETRY DURING ; OFFSET RECOVERY. ; ; P. J. CARR 27-AUG-82 16.03 ; ; PJC064 -- DON'T LOG MULTIPLE ERRORS DURING MULTI-BLOCK ; TRANSFERS THAT USE THE DBRTRY PATHWAY. ; ; P. J. CARR 27-AUG-82 16.04 ; ; PJC065 -- CORRECT HARD ECC RECOVERY ON THE LAST PARTIAL ; BLOCK OF A MULTI-BLOCK TRANSFER. ; ; P. J. CARR 27-AUG-82 16.05 ; ; PJC066 -- LOG THE UNSUCCESSFUL RECALIBRATE AFTER A SEEK ; FAILURE. ; ; P. J. CARR 27-AUG-82 16.06 ; ; PJC067 -- CORRECT THE BRANCH IN THE DATA LATE RECOVERY ; ROUTINE. ; ; J. GALLANT 2-MAR-83 16.07 ; ; JG0049 -- FIX THE CASE WHERE DTE AND DCK ARE COMBINED ; ; J. GALLANT 7-MAR-83 16.08 ; ; JG0041 -- FIX SO THAT A FMT AND OTHER I/O CAN OCCUR ; TOGETHER WITH OVERLAP SEEKS TURNED ON. ; MAKE RECALIBRATE A SEEK FUNCTION RATHER THAN ; A DATA TRANSFER FUNCTION. ; ; L. KOGAN 17-APR-84 16.09 ; ; LK001 -- ENTER NON-EXISTENT DRIVE ERROR INTO ; ERROR LOG FILE ; ; B. S. MCCARTHY 6-AUG-85 16.10 ; ; BM368 -- ADD CONDITIONAL SKIP OF FIRST DRIVE ; NOT READY ERROR FOR POWERFAIL ; ; MODIFIED FOR RSX-11M-PLUS V4.5 BY: ; ; D. CARROLL 27-SEP-1994 16.11 ; DC290 -- INCLUDE SUPPORT FOR THE SHELBY DRIVE ; AS A DYNAMICALLY SIZEABLE DEVICE ; ; D. CARROLL 21-MAR-95 16.12 ; DC320 -- DO NOT SEEK ON SHELBY, SINCE THE SEARCH ; FUNCTION IS A NO-OP FOR THE SHELBY ; ; ; RH11/RH70-RP04/05/06 OVERLAPPED SEEK DRIVER ; .MCALL HWDDF$,PKTDF$ HWDDF$ ;DEFINE HARDWARE REGISTERS PKTDF$ ;DEFINE I/O PACKET OFFSETS ; ; DEVICE REGISTER AND STATUS BIT DEFINITIONS ; RPCS1=0 ;CONTROL STATUS REGISTER 1 IE=100 ;INTERRUPT ENABLE TRE=40000 ;TRANSFER ERROR MCPE=20000 ;MASSBUS CONTROL PARITY ERROR DVA=4000 ;DRIVE AVAILABLE TO PORT RPWC=2 ;WORD COUNT REGISTER RPBA=4 ;BUFFER ADDRESS REGISTER RPDA=6 ;DESIRED TRACK/SECTOR REGISTER RPCS2=10 ;CONTROL STATUS REGISTER 2 DLT=100000 ;DATA LATE ERROR WCE=40000 ;WRITE CHECK ERROR UPE=20000 ;UNIBUS PARITY ERROR NED=10000 ;NONEXISTENT DISK ERROR NEM=4000 ;NONEXISTENT MEMORY ERROR PGE=2000 ;PROGRAMMING ERROR MXF=1000 ;MISSED TRANSFER ERROR MDPE=400 ;MASSBUS DATA PARITY ERROR RPDS=12 ;DRIVE STATUS REGISTER ERR=40000 ;ERROR SUMMARY BIT PIP=20000 ;POSITIONING IN PROGRESS MOL=10000 ;MEDIUM ONLINE WRL=4000 ;WRITE LOCKED DRIVE PGM=1000 ;PROGRAMMABLE PORT SELECT DPR=400 ;DRIVE PRESENT ON PORT DRY=200 ;DRIVE READY VV=100 ;VOLUME VALID RPER1=14 ;ERROR SUMMARY REGISTER DCK=100000 ;DATA CHECK ERROR UNS=40000 ;DRIVE UNSAFE OPI=20000 ;OPERATION INCOMPLETE DTE=10000 ;DRIVE TIMING ERROR WLE=4000 ;WRITE LOCK ERROR IAE=2000 ;INVALID DISK ADDRESS AOE=1000 ;ADDRESS OVERFLOW HCRC=400 ;HEADER CRC ERROR HCE=200 ;HEADER COMPARE ERROR ECH=100 ;ECC HARD ERROR WCF=40 ;WRITE CLOCK FAILURE FER=20 ;FORMAT ERROR CPE=10 ;CONTROL BUS PARITY ERROR RMR=4 ;REGISTER MODIFY REFUSED ILR=2 ;ILLEGAL REGISTER ILF=1 ;ILLEGAL FUNCTION RPAS=16 ;ATTENTION SUMMARY REGISTER RPDBR=22 ;DATA BUFFER REGISTER RPDT=26 ;DRIVE TYPE REGISTER RPOF=32 ;DRIVE OFFSET REGISTER FMT22=10000 ;FORMAT (1=16 BIT) ECI=4000 ;ECC INHIBIT HCI=2000 ;HEADER COMPARE INHIBIT RPDC=34 ;DESIREDED CYLINDER NUMBER RPCC=36 ;CURRENT CYLINDER NUMBER RPER2=40 ;ERROR REGISTER 2 RPEC1=44 ;ECC POSITION REGISTER RPEC2=46 ;ECC PATTERN REGISTER ; ; LOCAL EQUATED SYMBOLS ; XCT=1 ;FUNCTION HAS BEEN EXECUTED (1=YES) ERL=2 ;ERROR HAS BEEN LOGGED (1=YES) IHC=4 ;INHIBIT HEADER COMPARES (1=YES) ADR=10 ;ADDRESS BITS SETUP (1=YES) SEL=20 ;PORT SELECT WAIT (1=WAITING) OFA=100 ;OFFSET ACTIVE (1=YES) RETRY=8. ;CONTROLLER ERROR RETRY COUNT ; ; LOCAL DATA ; DELTA: .WORD 3 ;ROTATIONAL OPTIMIZATION DELTA ; ; CONTROLLER IMPURE DATA TABLES (INDEXED BY CONTROLER NUMBER) ; RTTBL: .BLKW R$$JP1 ;RETRY COUNT FOR CURRENT OPERATION OFFAD: .BLKW R$$JP1 ;ADDRESS OF CURRENT OFFSET VALUE PRMSV: .BLKW R$$JP1*5 ;PARAMETER SAVE AREA FOR ERROR RECOVERY AND ;WRITE CHECK SAVWC: .BLKW R$$JP1 ;SAVED WORD COUNT DLTWC: .BLKW R$$JP1 ;SAVED WORD COUNT FOR DATA LATE RECOVERY $DBOPT::.REPT R$$JP1 ;SEEK OPTIMIZATION TABLE .WORD 1 ;0=IMPLIED SEEK; 1=ALWAYS SEEK FIRST .ENDR ; ; OFFSET POSITIONING VALUE TABLE ; OFFTB: .WORD 0 ;RETURN TO CENTERLINE .WORD FMT22!20 ;+400 .WORD FMT22!220 ;-400 .WORD FMT22!40 ;+800 .WORD FMT22!240 ;-800 .WORD FMT22!60 ;+1200 .WORD FMT22!260 ;-1200 .WORD 0 ;RETURN TO CENTERLINE ; ; DIAGNOSTIC FUNCTION TABLE ; FUNTBL: .BYTE 107, IO.HMS!IQ.UMD&377 .BYTE 105, IO.BLS!IQ.UMD&377 .BYTE 115, IO.OFF!IQ.UMD&377 FUNTB0: .BYTE 173, IO.RDH!IQ.UMD&377 .BYTE 163, IO.WDH!IQ.UMD&377 .BYTE 151, IO.WCK!IQ.UMD&377 FUNTBE: ; ; DRIVER DISPATCH TABLE ; DDT$ DB,R$$JP1,,,,,,OPT ;GENERATE DISPATCH TABLE ;+ ; **-DBINI-RH11/RH70-RP04/05/06 DISK PACK CONTROLLER INITIATOR ; ; THIS IS THE DRIVER ENTRY POINT FROM THE QUEUE I/O DIRECTIVE WHEH AN ; I/O REQUEST IS QUEUED AND AT THE END OF A PREVIOUS I/O OPERATION TO ; PROPAGATE THE EXECUTION OF THE DRIVER. IF THE SPECIFIED UNIT IS NOT ; BUSY, THEN AN ATTEMPT IS MADE TO DEQUEUE THE NEXT I/O REQUEST. ELSE ; A RETURN TO THE CALLER IS EXECUTED. IF THE DEQUEUE ATTEMPT SUCCEEDS, ; THEN THE NEXT I/O OPERATION IS INITIATED AND A RETURN TO THE CALLER ; IS EXECUTED. ; ; INPUTS: ; ; R5=ADDRESS OF THE UCB OF THE UNIT TO BE INITIALIZED. ; ; OUTPUTS: ; ; IF THE SPECIFIED UNIT IS NOT BUSY AND AN I/O REQUEST IS WAITING ; TO BE PROCESSED, THEN THE REQUEST IS DEQUEUED AND THE I/O OPER- ; ATION IS INITIATED. ;- DBINI: GTPKT$ DB,R$$JP1 ;GET NEXT I/O PACKET TO PROCESS ; ; THE FOLLOWING ARGUMENTS ARE RETURNED BY $GTPKT: ; ; R1=ADDRESS OF THE I/O REQUEST PACKET. ; R2=PHYSICAL UNIT NUMBER OF THE REQUEST UCB. ; R3=CONTROLLER INDEX. ; R4=ADDRESS OF THE STATUS CONTROL BLOCK. ; R5=ADDRESS OF THE UCB OF THE UNIT TO BE INITIALIZED. ; ; RH11/RH70-RP04/05/06 DISK PACK I/O REQUEST PACKET FORMAT: ; ; WD. 00 -- I/O QUEUE THREAD WORD. ; WD. 01 -- REQUEST PRIORITY, EVENT FLAG NUMBER. ; WD. 02 -- ADDRESS OF THE TCB OF THE REQUESTOR TASK. ; WD. 03 -- POINTER TO SECOND LUN WORD IN REQUESTOR TASK HEADER. ; WD. 04 -- FIRST LUN WORD IN REQUESTORS TASK HEADER. ; WD. 05 -- I/O FUNCTION CODE. ; WD. 06 -- VIRTUAL ADDRESS OF I/O STATUS BLOCK. ; WD. 07 -- RELOCATION BIAS OF I/O STATUS BLOCK. ; WD. 10 -- I/O STATUS BLOCK ADDRESS (DISPLACEMENT + 140000). ; WD. 11 -- VIRTUAL ADDRESS OF AST SERVICE ROUTINE. ; WD. 12 -- MEMORY EXTENSION BITS (BITS 4 AND 5) OF I/O TRANSFER. ; WD. 13 -- BUFFER ADDRESS OF I/O TRANSFER. ; WD. 14 -- NUMBER OF BYTES TO BE TRANSFERED. ; WD. 15 -- DIAGNOSTIC SUPPLIMENTAL PARAMETER ELSE NOT USED. ; WD. 16 -- BITS <0:7> = HIGH LBN, BITS <8:15> NOT USED. ; WD. 17 -- LOW LBN OF I/O REQUEST. ; WD. 20 -- RELOCATION BIAS OF REGISTER BLOCK. ; WD. 21 -- REGISTER BLOCK ADDRESS (DISPLACEMENT + 140000). ; CLRB U.CW2+1(R5) ;RESET UNIT FLAGS CALL $VOLVD ;VALIDATE VOLUME VALID BCS 10$ ;IF CS WE FAILED TST R0 ;TRANSFER FUNCTION? BMI DBRQC ;IF MI YES JMP DBVV ;PROCESS VOLUME VALID FUNCTION 10$: CALL $IODON ;FINISH I/O BR DBINI ;GET NEXT REQUEST ; ; REQUEST CONTROLLER FOR PROPER OPERATION. ; DBRQC: MOV S.KRB(R4),R1 ;GET CURRENT KRB ADDRESS BIT #KS.POE,K.STS(R1) ;PARALLEL OPERATIONS ENABLED? BEQ DBRQC1 ;IF EQ NO MOV S.PKT(R4),R3 ;RETRIEVE I/O PACKET ADDRESS BITB #IQ.Q,I.FCN(R3) ; EXPRESS REQUEST ? BNE DBRQC1 ; IF NE YES BITB #IQ.UMD,I.FCN(R3) ; DIAGNOSTIC REQUEST ? BNE 20$ ; IF NE YES CMP U.PRM(R5),#<<32.*256.>+64.> ; SHELBY DRIVE? BEQ DBRQC1 ; YUP, DO NOT PERFORM SEEK OPERATION MOVB K.CON(R1),R3 ;RETREIVE CONTROLLER INDEX TST $DBOPT(R3) ;WHICH SEEK METHOD? BNE 10$ ;IF NE ALWAYS SEEK FIRST BIT #KS.DIP,K.STS(R1) ;DATA TRANSFER IN PROGRESS? BEQ DBRQC1 ;IF EQ NO, START DATA TRANSFER 10$: BISB #S3.SIP,S.ST3(R4) ;SET SEEK IN PROGRESS CALL $RQCNC ;REQUEST CONTROLLER FOR CONTROL FUNCTION BR DBINIO ; 20$: MOV #FUNTBL,R0 ; GET ADDRESS OF FUNCTION TABLE 25$: TSTB (R0)+ ; BYPASS CONTROLLER CODE CMPB (R0)+,I.FCN(R3) ; FUNCTION CODE MATCH ? BEQ 30$ ; IF EQ YES CMP #FUNTB0,R0 ; END OF TABLE ? BNE 25$ ; IF NE NO BR DBRQC1 ; YES, NORMAL TRANSFER FUNCTION 30$: TSTB -(R0) ; POINT BACK TO FUNCTION CODE MOVB -(R0),U.BUF(R5) ; LOAD CONTROLLER CODE BR 10$ ; TREAT AS A SEEK DBRQC1: BICB #S3.SIP,S.ST3(R4) ;SET SEEK ALREADY COMPLETED CALL $RQCND ;REQUEST CONTROLLER FOR DATA TRANSFER ; ; **-DBUBMP-SETUP UNIBUS ADDRESS ; ; THIS SECTION OF CODE WILL DETERMINE IF THE UNIBUS ADDRESS IS ; ALREADY IN THE FORMAT FOR THE MASSBUS CONTROLLER OR THE UNIBUS ; MAP FOR 22-BIT PROCESSORS WITHOUT RH CONTROLLERS. IT WILL ; ALSO CONVERT THE I/O FUNCTION CODE TO IT'S HARDWARE EQUIVALENT. ; ; NOTE: AT THIS POINT THE REQUESTING UNIT MUST BE THE OWNER OF ; THE CONTROLLER FOR A DATA TRANSFER. ; DBUBMP: MOV S.KRB(R4),R1 ;RETREIVE KRB ADDRESS BITB #ADR,U.CW2+1(R5);ADDRESS BITS ALREADY SETUP? BNE DBINIO ;IF NE YES BIT #FE.EXT,$FMASK ;22-BIT ADDRESSING ENABLED? BEQ 10$ ;IF EQ NO BIT #KS.MBC,K.STS(R1) ;YES, IS THIS A 22-BIT CONTROLLER? BNE 20$ ;IF NE YES CALL $STMAP ;SETUP UNIBUS MAP ADDRESS 10$: ASL U.BUF(R5) ;SHIFT BITS <4:5> TO BITS <8:9> ASL U.BUF(R5) ;... ASL U.BUF(R5) ;... ASL U.BUF(R5) ;... BIT #FE.EXT,$FMASK ;22-BIT ADDRESSING ENABLED? BEQ 20$ ;IF EQ NO CALL $MPUBM ;MAP UNIBUS TO TRANSFER 20$: BISB #ADR,U.CW2+1(R5);INDICATE ADDRESS SETUP COMPLETE ; ; CONVERT I/O FUNCTION CODE TO HARDWARE EQUIVALENT. ; MOV S.PKT(R4),R1 ;RETREIVE I/O PACKET ADDRESS CMPB #IO.HMS/256.,I.FCN+1(R1) ;DIGNOSTIC FUNCTION? BNE 40$ ;IF NE NO MOV #FUNTBL,R0 ;GET ADDRESS OF FUNCTION TABLE 30$: MOVB (R0)+,U.BUF(R5) ;LOAD CONTROLLER FUNCTION CODE CMPB (R0)+,I.FCN(R1) ;IS IT THE CORRECT CODE? BEQ 60$ ;IF EQ YES CMP #FUNTBE,R0 ;END OF FUNCTION TABLE? BNE 30$ ;IF NE NO 40$: MOV #IE.IFC&377,R0 ;ASSUME ILLEGAL FUNCTION MOVB #171,U.BUF(R5) ;ASSUME READ LOGICAL FUNCTION CMPB #IO.RLB/256.,I.FCN+1(R1) ;READ LOGICAL FUNCTION? BHIS 50$ ;IF HIS FUNCTION IS LEGAL MOV @S.KRB(R4),R2 ;RETREIVE CSR ADDRESS MOVB U.UNIT(R5),RPCS2(R2) ;SELECT THE UNIT JMP DBFIN1 ;FINISH I/O 50$: BEQ 60$ ;IF EQ YES MOVB #161,U.BUF(R5) ;SET WRITE LOGICAL FUNCTION 60$: MOV S.KRB(R4),R3 ;RETRIEVE KRB ADDRESS MOVB K.CON(R3),R3 ;RETRIEVE CONTROLLER INDEX MUL #5,R3 ;SETUP INDEX INTO ... ADD #PRMSV,R3 ;... PARAMETER AREA MOV U.BUF(R5),(R3)+ ;SAVE PARAMETERS MOV U.BUF+2(R5),(R3)+ ;... MOV U.CNT(R5),(R3)+ ;... MOV I.PRM+10(R1),(R3)+ ;... MOV I.PRM+12(R1),(R3)+ ;... ; ; **-DBINIO-INITIATE AN I/O OPERATION ; ; THIS ROUTINE WILL INITIATE EITHER A SEEK OR THE DATA TRANSFER OPER- ; ATION DEPENDING ON HOW THE CONTROLLER WAS REQUESTED. ; ; INPUTS: ; ; R4=ADDRESS OF THE SCB. ; R5=ADDRESS OF THE UCB. ; DBINIO: MOV @S.KRB(R4),R2 ;GET CSR ADDRESS MOV S.PKT(R4),R1 ;GET I/O PACKET ADDRESS MOVB U.UNIT(R5),RPCS2(R2) ;SELECT UNIT ; ; DETERMINE IF DRIVE'S PORT IS SEIZED BY THIS CONTROLLER. ; MTPS #PR5 ;EXECUTE AT DEVICE PRIORITY CLR RPDS(R2) ;;;ATTEMPT TO SEIZE THE DRIVE BIT #DPR,RPDS(R2) ;;;DID THE DRIVE SEIZE? BNE 5$ ;;;IF NE YES BISB #SEL,U.CW2+1(R5);;;SET PORT SELECT WAIT FLAG MOVB S.ITM(R4),S.CTM(R4) ;;;SET TIMEOUT COUNT CLR S.FRK+2(R4) ;;;ALLOW INTERRUPTS MOVB #IE,(R2) ;;;RE-ENABLE INTERRUPTS MTPS #0 ;;;ALLOW INTERRUPTS CALLR $RLCN ;RELEASE CONTROLLER AND EXIT ; ; CHECK IF THE HEADS ARE ON THE CORRECT CYLINDER. ; 5$: MOVB #111,(R2) ;;;CLEAR SELECTED DRIVE BITB #S3.SIP,S.ST3(R4) ;;;ARE WE DOING A SEEK? BEQ 10$ ;;;IF EQ NO BITB #IQ.UMD,I.FCN(R1) ;;; DIAGNOSTIC FUNCTION ? BNE 20$ ;;; IF NE YES CMP RPCC(R2),I.PRM+10(R1) ;;;DO WE NEED TO SEEK? BNE 20$ ;;;IF NE YES MTPS #0 ;ENABLE INTERRUPTS JMP DBRQC1 ;GO REQUEST CONTROLLER ; ; LOAD CONTROLLER REGISTERS FOR DATA TRANSFER. ; 10$: ADD #RPCS2,R2 ;;;POINT TO SECOND CSR REGISTER MOV I.PRM+12(R1),-(R2) ;;;INSERT TRACK/SECTOR ADDRESS MOV U.BUF+2(R5),-(R2) ;;;INSERT BUFFER ADDRESS MOV U.CNT(R5),-(R2) ;;;INSERT NUMBER OF BYTES TO TRANSFER ROR (R2) ;;;CONVERT TO WORD COUNT NEG (R2) ;;;MAKE NEGATIVE WORD COUNT TST -(R2) ;;;POINT BACK TO RPCS1 20$: MOV #FMT22,R3 ;;;FORCE 16-BIT MODE CMP #IO.OFF!IQ.UMD,I.FCN(R1) ;;;DIAG. OFFSET FUNCTION? BNE 30$ ;;;IF NE NO BIS I.PRM+6(R1),R3 ;;;YES, MERGE OFFSET VALUE 30$: BITB #IHC,U.CW2+1(R5);;;INHIBIT HEADER COMPARE? BEQ 40$ ;;;IF EQ NO BIS #HCI,R3 ;;;SET HEADER COMPARE INHIBIT 40$: MOV R3,RPOF(R2) ;;;SET OFFSET REGISTER ; ; CHECK FOR DRIVE NOT READY CONDITIONS. ; MOV #IE.DNR&377,R0 ;;;ASSUME DRIVE NOT READY MOV I.PRM+10(R1),RPDC(R2) ;;;SET DESIRED CYLINDER ADDRESS MOV RPDS(R2),R3 ;;;GET CURRENT DRIVE STATUS COM R3 ;;;COMPLEMENT STATUS BIT #MOL!DRY,R3 ;;;DRIVE READY AND ON LINE? BNE 50$ ;;;IF NE NO BIT #UNS,RPER1(R2) ;;;DRIVE UNSAFE? BEQ 70$ ;;;IF EQ NO 50$: MTPS #0 ;;;ALLOW INTERRUPTS BITB #US.SPU,U.STS(R5) ;IS DRIVE SPINNING UP? BEQ 55$ ;IF EQ NO BITB #US.VV,U.STS(R5);WAS VOLUME PREVIOUSLY MOUNTED? BEQ 52$ ;;; IF EQ NO BR DBPWF0 ;YES, WAIT FOR IT TO SPIN UP 52$: JMP DBPWF1 ;;; 55$: BITB #IQ.UMD,I.FCN(R1) ;DIAGNOSTIC OPERATION? BEQ 60$ ;IF EQ NO JMP DBDIAG ;PASS REGISTERS AND FINISH I/O 60$: ;REFERENCE LABEL .IF DF S2.NRD BIT #S2.NRD,S.ST2(R4) ;IS THIS FIRST DRIVE NOT READY? BNE 61$ ;IF NE NO, GO LOG ERROR BIS #S2.NRD,S.ST2(R4) ;INDICATE FIRST DRIVE NOT READY JMP DBPWF1 ;GO DO A RETRY 61$: BIC #S2.NRD,S.ST2(R4) ;CLEAR FIRST DRIVE NOT READY .ENDC ; DF S2.NRD CALL $DVERR ;LOG DRIVE NOT READY ERROR 65$: JMP DBFIN1 ;FINISH I/O 70$: BIT #VV,R3 ;;;DID VOLUME VALID CHANGE? BEQ 75$ ;;;IF EQ NO (NOTE REVERSE STATUS OF VV) BITB #US.SPU,U.STS(R5) ;;;DID WE JUST SPIN UP? BEQ 50$ ;;;IF EQ NO MOVB #123,(R2) ;;;YES, RESET VOLUME VALID BISB #US.VV,U.STS(R5);;;SET SOFTWARE VOLUME VALID 75$: BIT #S2.MAD,S.ST2(R4) ;;;MULTI-ACCESS DEVICE? BEQ 90$ ;;;IF EQ NO CMP S.KRB(R4),S.KTB(R4) ;;;IS THIS PORT 'A'? BNE 80$ ;;;IF NE NO BICB #S3.SPA,S.ST3(R4) ;;;YES, SHOW IT SPUN UP BR 85$ ;;; 80$: BICB #S3.SPB,S.ST3(R4) ;;;IT MUST BE PORT 'B' 85$: BITB #S3.SPU,S.ST3(R4) ;;;BOTH PORTS SPUN UP? BNE 95$ ;;;IF NE NO ; ; PREPARE TO START AN I/O OPERATION. ; 90$: BICB #US.SPU,U.STS(R5) ;;;RESET DRIVE SPINNING UP 95$: CLR S.FRK+2(R4) ;;;INIT FORK INTERLOCK MOVB S.ITM(R4),S.CTM(R4) ;;;SET TIMEOUT COUNT BIS #S2.ACT,S.ST2(R4) ;;;SHOW I/O IS ACTIVE BISB #XCT,U.CW2+1(R5);;;SHOW FUNCTION BEING EXECUTED BITB #S3.SIP,S.ST3(R4) ;;;SHOULD WE DO A SEEK? BEQ 105$ ;;;IF EQ NO ; ; START EXPLICIT SEEK. ; BITB #IQ.UMD,I.FCN(R1) ;;; DIAGNOSTIC FUNCTION ? BEQ 99$ ;;; IF EQ NO MOVB U.BUF(R5),(R2) ;;; LOAD POSITION FUNCTION BR 101$ ;;; 99$: MOVB U.PRM(R5),R3 ;;; GET SECTORS/TRACK CLR -(SP) ;;;CLEAR A WORD MOVB I.PRM+12(R1),(SP) ;;;GET DESIRED SECTOR ADDRESS SUB DELTA,(SP) ;;;SUBTRACT ROTATIONAL DELTA BPL 100$ ;;;IF PL ADJUSTMENT WAS OK ADD R3,(SP) ;;;CORRECT ADJUSTMENT IF NEGATIVE 100$: MOVB I.PRM+13(R1),1(SP) ;;;SET DESIRED TRACK ADDRESS MOV (SP)+,RPDA(R2) ;;;LOAD ADJUSTED TRACK/SECTOR ADDRESS MOVB #131,(R2) ;;;LOAD THE SEARCH FUNCTION 101$: MTPS #0 ;;; ALLOW INTERRUPTS BR DBPWF3 ;RELEASE CONTROLLER AND EXIT ; ; START DATA TRANSFER. ; 105$: MOV S.KRB(R4),R3 ;;;GET CURRENT KRB ADDRESS BIT #IQ.UMD,I.FCN(R1) ;;;IS IT A DIAGNOSTIC FUNCTION? BEQ 106$ ;;;IF EQ NO CMPB U.BUF(R5),#140 ;;;IS IT A UMD SEEK FUNCTION? BLO 107$ ;;;IF LO YES 106$: BIS #KS.DIP,K.STS(R3) ;;;SET DATA TRANSFER IN PROGRESS BIT #FE.EXT,$FMASK ;;;22-BIT ADDRESSING ENABLED? BEQ 110$ ;;;IF EQ NO BIT #KS.MBC,K.STS(R3) ;;;IS THIS A 22-BIT CONTROLLER? BEQ 110$ ;;;IF EQ NO MOV R3,R1 ;;;COPY KRB ADDRESS ADD K.OFF(R3),R1 ;;;POINT TO UCB TABLE MOV KE.RHB(R1),R1 ;;;RETREIVE RHBAE OFFSET ADD R2,R1 ;;;FORM AN I/O PAGE ADDRESS MOVB U.BUF+1(R5),(R1);;;SET MEMORY EXTENSION BITS 107$: MOVB U.BUF(R5),(R2) ;;;START FUNCTION BR 120$ ;;; 110$: MOV U.BUF(R5),(R2) ;;;START FUNCTION 120$: MTPS #0 ;ALLOW INTERRUPTS ; ; CANCEL I/O OPERATION IS A NOP FOR FILE STRUCTURED DEVICES. ; DBCAN: RETURN ;;;NOP FOR RP04/05/06 ;+ ; POWERFAIL IS HANDLED VIA THE DEVICE TIMEOUT FACILITY AND ; CAUSES NO IMMEDIATE ACTION ON THE UNIT. THE CURRENT TIMEOUT ; COUNT IS EXTENDED SO THAT IF THE UNIT WAS BUSY IT WILL HAVE ; SUFFICIENT TIME TO SPIN BACK UP. THE NEXT I/O REQUEST TO ANY ; UNIT WILL BE SUSPENDED FOR AT LEAST THE EXTENDED TIMEOUT UNLESS ; THE UNIT IS ALREADY READY. ;- DBPWF: TSTB S.STS(R4) ;IS THIS UNIT CURRENTLY BUSY? BEQ DBPWF2 ;IF EQ NO DBPWF0: MOVB #15.,S.STS(R4) ;WAIT A MAXIMUM OF ONE MINUTE DBPWF1: MOVB S.ITM(R4),S.CTM(R4) ;4 SECONDS AT A TIME DBPWF2: BISB #US.SPU,U.STS(R5) ;SET UNIT SPINNING UP DBPWF3: CALLR $RLCN ;RELEASE CONTROLLER AND EXIT ;+ ; **-$DBINT-RH11/RH70-RP04/05/06 DISK PACK CONTROLLER ; INTERRUPT HANDLER ;- .ENABL LSB $DBINT::BR DBFRK ;;;ENTRY POINT FOR DATA TRANSFERS TST S.FRK+2(R4) ;;;ARE INTERRUPTS ALLOWED? BNE DBCAN ;;;IF NE NO, IGNORE IT CALL $FORK ;;;CREATE A SYSTEM PROCESS DBFRK: BITB #SEL,U.CW2+1(R5);WAITING FOR PORT TO SELECT? BEQ 5$ ;IF EQ NO BICB #SEL,U.CW2+1(R5);RESET PORT SELECT FLAG MOV U.SCB(R5),R4 ;YES, RETREIVE SCB ADDRESS MOV S.PKT(R4),R3 ;RETREIVE I/O PACKET ADDRESS JMP DBRQC ;GO TRY AGAIN 5$: CALL $RQCND ;REQUEST CONTROLLER FOR DATA TRANSFER MOV S.KRB(R4),R3 ;GET CURRENT KRB ADDRESS MOVB K.CON(R3),R3 ;RETREIVE CONTROLLER INDEX MOV @S.KRB(R4),R2 ;GET CSR ADDRESS MOVB U.UNIT(R5),RPCS2(R2) ;SELECT UNIT TSTB S.STS(R4) ;IS THIS UNIT BUSY? BNE 10$ ;IF NE YES MTPS #PR5 ;EXECUTE AT DEVICE PRIORITY CLR S.FRK+2(R4) ;;;RESET FORK INTERLOCK MOV #TRE!11,(R2) ;;;CLEAR CONTROLLER AND DRIVE BISB #S3.DRL,S.ST3(R4) ;;;SHOW DUAL ACCESS UNIT RELEASED MOVB #113,(R2) ;;;RELEASE DRIVE MTPS #0 ;;;ALLOW INTERRUPTS BR DBPWF3 ;RELEASE CONTROLLER ; ; INTERRUPT WAS FROM A BUSY UNIT. IF WE JUST DID A SEEK WE WILL ; GO AND START THE DATA TRANSFER OPERATION. IF THE DATA TRANSFER ; TERMINATED, DETERMINE WHY. IF WE ARE SPINNING UP, RETRY THE ; OPERATION. ; 10$: BITB #US.SPU,U.STS(R5) ;ARE WE SPINNING UP? BEQ 15$ ;IF EQ NO BIT #S2.MAD,S.ST2(R4) ;MULTI-ACCESS DEVICE? BEQ 12$ ;IF EQ NO CMP S.KRB(R4),S.KTB(R4) ;IS THIS PORT 'A'? BNE 14$ ;IF NE NO BITB #S3.SPA,S.ST3(R4) ;IS PORT 'A' SPINNING UP? BEQ 15$ ;IF EQ NO 12$: CALLR 100$ ;RETRY THE OPERATION 14$: BITB #S3.SPB,S.ST3(R4) ;IS PORT 'B' SPINNING UP? BNE 12$ ;IF NE YES 15$: BIT #S2.EIP,S.ST2(R4) ;ERROR ALREADY IN PROGRESS? BNE 20$ ;IF NE YES CALL DBPRM ;SET INITIAL RETRY VALUES 20$: MOV S.PKT(R4),R1 ; GET I/O PACKET ADDRESS MOV #IS.SUC&377,R0 ; ASSUME SUCESSFUL TRANSFER BITB #S3.SIP,S.ST3(R4) ; DID WE JUST DO A SEEK ? BEQ 30$ ;IF EQ NO BICB #S3.SIP,S.ST3(R4) ;CLEAR SEEK IN PROGRESS BITB #IQ.UMD,I.FCN(R1) ; DIAGNOSTIC FUNCTION EXECUTED ? BNE DBDIAG ; IF NE YES BIT #ERR,RPDS(R2) ;ANY ERRORS DURING THE SEEK? BEQ 100$ ;IF EQ NO CALL $DVERR ;LOG THE SEEK ERROR DECB RTTBL(R3) ;COUNT THIS RETRY CALL DBERL ;FINISH ERROR LOGGING 25$: MOV #TRE!11,(R2) ;CLEAR CONTROLLER AND DRIVE MOV #107,R1 ;SET RECALIBRATE FUNCTION CALLR DBFUNC ;ISSUE THE RECALIBRATE AND EXIT ; ; INTERRUPT WAS DUE TO A DATA TRANSFER OPERATION OR DIAGNOSTIC FUNCTION ; 30$: BITB #IQ.UMD,I.FCN(R1) ; DIAGNOSTIC FUNCTION EXECUTED ? BNE DBDIAG ;IF NE YES BIT #60,(R2) ;POSITIONING FUNCTION? BEQ 80$ ;IF EQ YES BIT #TRE!MCPE,(R2) ;ANY ERRORS? BEQ 70$ ;IF EQ NO MOV RPWC(R2),R0 ;GET NEGATIVE WORDS REMAINING MOV R0,SAVWC(R3) ;SAVE IT FOR LATER USE CLR DLTWC(R3) ;ZERO DLT FLAG WORD TST RPCS2(R2) ;DATA LATE ERROR? BPL 35$ ;IF PL NO MOV R0,DLTWC(R3) ;YES, SAVE REAL NEGATIVE WORDS REMAINING BNE 35$ ;IF NE WE HAD A PARTIAL TRANSFER MOV #-1,DLTWC(R3) ;DLT ON LAST WORD, FAKE A PARTIAL XFR 35$: ASL R0 ;CONVERT TO NEGATIVE BYTES ADD U.CNT(R5),R0 ;CALCULATE BYTES ACTUALLY TRANSFERED SUB #512.,R0 ;SUBTRACT OUT BLOCK IN ERROR BLE 40$ ;IF LE NO GOOD BYTES TRANSFERED BITB #ERL,U.CW2+1(R5);ERROR ALREADY IN PROGRESS? BEQ 40$ ;IF EQ NO ; ; WE GOT AN ERROR BUT SOME GOOD DATA WAS TRANSFERED. THIS ; INDICATES THAT WE RECOVERED FROM THE PREVIOUS ERROR. ; CALL DBERL ;FINISH ERROR LOGGING 40$: CALL $DVERR ;LOG DEVICE ERROR BISB #ERL,U.CW2+1(R5);SET ERROR LOGGED FLAG MOV #IE.WLK&377,R0 ;ASSUME WRITE LOCK ERROR BIT #WLE,RPER1(R2) ;WRITE LOCK ERROR? BNE 60$ ;IF NE YES MOV #IE.VER&377,R0 ;ASSUME UNRECOVERABLE ERROR BITB #IQ.X,I.FCN(R1) ;INHIBIT RETRIES? BNE 60$ ;IF NE YES TST DLTWC(R3) ;REAL DATA LATE ERROR? BNE 110$ ;IF NE YES MOV RPER1(R2),R1 ;GET CONTENTS OF ERROR REGISTER BIT #UNS!IAE!AOE!RMR!ILR!ILF,R1 ;HARD ERROR? BNE 60$ ;IF NE YES BIT #NED!NEM,RPCS2(R2) ;HARD ERROR? BNE 60$ ;IF NE YES BIT #HCE,R1 ;HEADER COMPARE ERROR? BNE 25$ ;IF NE YES, DO A RECALIBRATE BIT #WCE!UPE!PGE!MXF!MDPE,RPCS2(R2) ;CONTROLLER ERROR? BNE DBRTRY ;IF NE YES, RETRY OPERATION JMP DBECC ;CHECK FOR ECC ERRORS DBDIAG: CALL $CRPAS ;PASS CONTROLLER REGISTERS TO TASK CALL DBCLR ;CLEAR SELECTED DRIVE 60$: JMP DBFIN ;FINISH I/O 70$: JMP DBWCHK ;GO TEST FOR A WRITE CHECK ; ; PROCESS POSITIONING OPERATION. ; 80$: MOV #IE.VER&377,R0 ;ASSUME UNRECOVERABLE ERROR BIT #ERR,RPDS(R2) ;ERRORS DURING POSITIONING? BEQ 85$ ;IF EQ NO CALL $DVERR ;LOG IT CLR R1 ;SHOW NO BYTES TRANSFERED JMP DBFIN1 ;FINISH I/O 85$: BIT #10,(R2) ;RECALIBRATE FUNCTION? BNE 95$ ;IF NE NO 90$: BIT #PIP,RPDS(R2) ;IS THE RECAL REALLY DONE? BNE 90$ ;IF NE NO, LOOP FOR IT BR DBRTRY ;NOW RETRY THE FUNCTION 95$: CMP #OFFTB+16,OFFAD(R3) ;FINAL OFFSET TRIED? BEQ 60$ ;IF EQ YES 100$: CALL DBCLR ;CLEAR SELECTED DRIVE CALLR DBUBMP ;RETRY ORIGINAL FUNCTION ; ; THE TRANSFER WAS STOPPED DUE TO A DATA LATE ERROR CONDITION. ; WE WILL NOW BACKUP THE WORD COUNT, BUS ADDRESS AND CYLINDER/ ; TRACK/SECTOR ADDRESS BY ONE BLOCK AND RETRY THE TRANSFER FROM ; THIS POINT. THIS IS DONE TO PREVENT THE DATA LATE CONDITION ; FROM RECURRING DUE TO A LONG TRANSFER. ; 110$: DECB RTTBL(R3) ;RETRY DATA LATE CONDITION? BLE 60$ ;IF LE NO MOV DLTWC(R3),R0 ;GET REAL NEGATIVE WORDS REMAINING ASL R0 ;CONVERT TO NEGATIVE BYTES ADD U.CNT(R5),R0 ;CALCULATE BYTES ACTUALLY TRANSFERED BIC #777,R0 ;GET BLOCKS ACTUALLY TRANSFERED CALL DBCALC ;BACKUP TO START OF BLOCK IN ERROR TST U.CNT(R5) ;DLT ERROR ON LAST BLOCK? BNE 100$ ;IF NE NO ADD R0,U.CNT(R5) ;YES, BACKUP BYTES TO TRANSFER BR 100$ ;RESTART THE TRANSFER .DSABL LSB ;+ ; DEVICE TIMEOUT RESULTS IN THE CURRENT OPERATION BEING REPEATED ; UNLESS THE OPERATION WAS DIAGNOSTIC. TIMEOUTS ARE USUALLY CAUSED ; BY POWERFAILURE BUT MAY ALSO BE THE RESULT OF A HARDWARE FAILURE. ;- .ENABL LSB DBOUT: BITB #US.SPU,U.STS(R5) ;;;IS DRIVE SPINNING UP? BEQ 15$ ;;;IF EQ NO BIT #S2.MAD,S.ST2(R4) ;;;MULTI-ACCESS DEVICE? BEQ 10$ ;;;IF EQ NO CMP S.KRB(R4),S.KTB(R4) ;;;IS THIS PORT 'A'? BNE 5$ ;;;IF NE NO, IT MUST BE PORT 'B' BITB #S3.SPA,S.ST3(R4) ;;;IS PORT 'A' SPINNING UP? BNE 10$ ;;;IF NE YES BR 15$ ;;;TIMEOUT FOR NORMAL OPERATION 5$: BITB #S3.SPB,S.ST3(R4) ;;;IS PORT 'B' SPINNING UP? BEQ 15$ ;;;IF EQ NO 10$: DECB S.STS(R4) ;;;HAVE WE WAITED ENOUGH YET? BEQ 15$ ;;;IF EQ YES MTPS #0 ;;;ALLOW INTERRUPTS MOV S.PKT(R4),R3 ;RETREIVE I/O PACKET ADDRESS JMP DBRQC ;RETRY OPERATION 15$: INCB S.STS(R4) ;;;LEAVE CONTROLLER BUSY MTPS #0 ;;;ALLOW INTERRUPTS MOV S.PKT(R4),R1 ;GET I/O PACKET ADDRESS CALL $RQCND ;REQUEST CONTROLLER FOR DATA TRANSFER MOV S.KRB(R4),R2 ;GET CURRENT KRB ADDRSS MOVB K.CON(R2),R3 ;RETREIVE CONTROLLER INDEX MOV (R2),R2 ;GET CSR ADDRESS MOVB U.UNIT(R5),RPCS2(R2) ;SELECT UNIT FOR ERROR LOGGING CALL $DVTMO ;LOG DEVICE TIMEOUT ; ; NOTE: THE FOLLOWING SIX INSTRUCTIONS (AND THE SUBROUTINE) DO ; NOT CHANGE THE C-BIT SETTING RETURNED FROM $DVTMO. ; BITB #SEL,U.CW2+1(R5);WAITING FOR PORT TO SELECT? BNE DBFIN1 ;IF NE YES, WE DIDN'T GET IT BITB #S3.SIP,S.ST3(R4) ;TIMEOUT DURING A SEEK? BEQ 20$ ;IF EQ NO CALL DBPRM ;RESET RETRY PARAMETERS 20$: BICB #S3.SIP,S.ST3(R4) ;ASSUME DATA TRANSFER FUNCTION BCS DBDIAG ;IF CS TIMEOUT DURING DIAGNOSTIC BITB #US.SPU,U.STS(R5) ;WAS THE DRIVE SPINNING UP? BEQ DBRTRY ;IF EQ NO MOV #IE.DNR&377,R0 ;YES, SET DRIVE NOT READY BR DBFIN ;FINISH I/O DBRTRY: MOV S.PKT(R4),R1 ;GET I/O PACKET ADDRESS BICB #ERL,U.CW2+1(R5) ;CAN'T CLOSE ERRORS RETRIED FROM BEG BIT #WCE,RPCS2(R2) ;WRITE CHECK ERROR? BEQ 25$ ;IF EQ NO MOV #IE.WCK&377,R0 ;YES, SET WRITE CHECK ERROR 25$: BITB #IQ.X,I.FCN(R1) ;INHIBIT RETRIES? BNE DBFIN ;IF NE YES DECB RTTBL(R3) ;RETRY FUNCTION? BGT 40$ ;IF GT YES BR DBFIN ;FINISH I/O ; ; TEST FOR WRITE CHECK OPERATION. ; DBWCHK: BITB #IO.WLC&377,I.FCN(R1) ;WRITE FOLLOWED BY WRITE CHECK? BNE 30$ ;IF NE YES BITB #US.WCK,U.STS(R5) ;WRITE CHECK ENABLED BY MCR? BEQ DBFIN ;IF EQ NO 30$: CMPB #171,U.BUF(R5) ;WAS LAST FUNCTION A READ? BEQ DBFIN ;IF EQ YES CMPB #161,U.BUF(R5) ;WAS LAST FUNCTION A WRITE? BNE DBFIN ;IF NE NO MOV #RETRY,RTTBL(R3) ;REINITIALIZE RETRY COUNT MUL #5,R3 ;CREATE INDEX INTO ... ADD #PRMSV,R3 ;... PARAMETER SAVE AREA MOV (R3)+,U.BUF(R5) ;RESTORE PARAMETERS MOV (R3)+,U.BUF+2(R5) ;... MOV (R3)+,U.CNT(R5) ;... MOV (R3)+,I.PRM+10(R1) ;... MOV (R3)+,I.PRM+12(R1) ;... MOVB #151,U.BUF(R5) ;SET WRITE CHECK FUNCTION 40$: CALL DBCLR ;CLEAR THE SELECTED DRIVE CALLR DBUBMP ;START THE WRITE CHECK OPERATION .DSABL LSB ; ; **-DBFIN-FINISH I/O OPERATION ; ; THIS ROUTINE WILL SET THE ACTUAL BYTES TRANSFERED PARAMETER, THE ; ERROR LOGGING RETRY COUNTS AND CALL $IODON. THE SELECTED DRIVE ; IS RELEASED, IF REQUESTED, AND THE CONTROLLER IS RELEASED. ; ; INPUTS: ; ; R0=SUCCESS/ERROR CODE ; R2=ADDRESS OF CONTROLER CSR ; R4=ADDRESS OF THE SCB ; R5=ADDRESS OF THE UCB ; DBFIN: MOV S.PKT(R4),R3 ;GET I/O PACKET ADDRESS MOV RPWC(R2),R1 ;GET WORDS REMAINING TO TRANSFER ASL R1 ;CONVERT TO BYTES LEFT TO TRANSFER ADD I.PRM+4(R3),R1 ;CALCULATE BYTES ACTUALLY TRANSFERED DBFIN1: CALL DBCLR1 ;CLEAR THE SELECTED DRIVE MOV #TRE,(R2) ;NOW CLEAR THE CONTROLLER BICB #SEL,U.CW2+1(R5);CLEAR PORT SELECT FLAG MOV S.KRB(R4),R3 ;GET CURRENT KRB ADDRESS ; ; CHECK FOR ATTENTIONS AND RELEASE DRIVE. ; 10$: TSTB RPAS(R2) ;ANY ATTENTIONS PENDING? BEQ 20$ ;IF EQ NO BISB #IE,(R2) ;YES, FORCE CALL TO INTERRUPT HANDLER BR 10$ ;TRY AGAIN 20$: BITB #S3.NRL,S.ST3(R4) ;SHOULD WE RELEASE THE DRIVE? BEQ 30$ ;IF EQ YES MOVB #IE,(R2) ;NO, JUST RE-ENABLE INTERRUPTS BR 40$ ; 30$: BISB #S3.DRL,S.ST3(R4) ;SHOW DUAL ACCESS UNIT RELEASED MOVB #113,(R2) ;RELEASE THE DRIVE 40$: MOVB K.CON(R3),R3 ;RETREIVE CONTROLLER INDEX MOVB RTTBL(R3),R2 ;GET FINAL ERROR RETRY COUNT BITB #XCT,U.CW2+1(R5);HAS A FUNCTION BEEN EXECUTED? BNE 50$ ;IF NE YES MOV #RETRY,R2 ;SET MAXIMUM RETRY COUNT 50$: BIS #RETRY*256.,R2 ;MERGE STARTING RETRY COUNT BICB #S3.SIP,S.ST3(R4) ;RESET SEEK IN PROGRESS FLAG DBFIN2: CALL $RLCN ;RELEASE THE CONTROLLER CALL $IODON ;FINISH I/O OPERATION JMP DBINI ;PROCESS NEXT REQUEST ; ; **-DBECC-ATTEMPT ECC CORRECTION ; ; THIS ROUTINE IS ENTERED IF A DATA ERROR IS DETECTED. IF THE ERROR ; IS CORRECTABLE, THE EXECUTIVE ECC ROUTINE IS CALLED AND THE OPERATION ; IS RESTARTED FROM WHERE THE CONTROLLER STOPPED. IF OFFSET RECOVERY ; IS REQUIRED, WE WILL DO IT. ; ; INPUTS: ; ; R1=CONTENTS OF RPER1 ; R2=ADDRESS OF CONTROLLER CSR ; DBECC: BIT #DCK!DTE!HCRC,R1;CORRECTABLE ERROR? BEQ DBRTRY ;IF EQ NO CMPB #171,U.BUF(R5) ;IS THIS A READ OPERATION? BNE DBRTRY ;IF NE NO MOV SAVWC(R3),R0 ;GET NEGATIVE # OF WORDS REMAINING ASL R0 ;CONVERT TO BYTES ADD U.CNT(R5),R0 ;CALCULATE BYTES ACTUALLY TRANSFERED BEQ DBOFF ;IF EQ NONE TRANSFERED, TRY OFFSET BIS RPER2(R2),R1 ;.OR. ERROR REGISTER 2 CMP #DCK,R1 ;ONLY DATA CHECK ERROR? BNE DBOFF ;IF NE NO, TRY OFFSET MOV SAVWC(R3),-(SP) ;PUT REMAINING WORD COUNT ON STACK MOV RPEC1(R2),R1 ;GET ECC ERROR POSITION MOV RPEC2(R2),R3 ;GET ECC CORRECTION PATTERN MOV (SP)+,R2 ;GET REMAINING WORD COUNT CALL $ECCOR ;DO ECC CORRECTION CALL DBCLR ;CLEAR SELECTED DRIVE CALL DBPRM0 ;RESET OFFSET RECOVERY PARAMETERS CALL DBCALC ;RE-CALCULATE DISK ADDRESS MOV #IS.SUC&377,R0 ;ASSUME NO MORE WORDS TO TRANSFER TST U.CNT(R5) ;ANY MORE WORDS TO TRANSFER? BEQ DBFIN ;IF EQ NO DBREST: CALLR DBINIO ;RESTART THE TRANSFER ; ; **-DBOFF-ATTEMPT OFFSET RECOVERY ; ; THIS ROUTINE IS CALLED WHENEVER WE NEED TO OFFSET THE HEADS ; SOME DISTANCE FROM TRACK CENTERLINE TO PROPERLY READ THE DATA. ; ; INPUTS: ; ; R0=NUMBER OF BYTES ACTUALLY TRANSFERED TO THIS POINT ; DBOFF: BITB #OFA,U.CW2+1(R5) ;OFFSET ALREADY ACTIVE? BNE 5$ ;IF NE YES DECB RTTBL(R3) ;ANY RETRIES LEFT? BGT 5$ ;IF GT YES MOV #IE.VER&377,R0 ;SET UNRECOVERABLE ERROR JMP DBFIN ;FINISH I/O 5$: TST R0 ; ANYTHING TRANSFERRED ? BEQ 20$ ; NO BIT #ECH!DTE,RPER1(R2); HARD ECC OR DTE ERROR ? BEQ 15$ ; NO DEC R0 ;BACK UP TO THE PREVIOUS BLOCK... ; OR CURRENT IF NOT ON BLOCK BOUNDARY BIC #777,R0 ; FORCE TO A BLOCK BOUNDARY ; Z-BIT SET BY BIC IF R0 IS 0 BEQ 20$ ;IF EQ NO ; ; THE TRANSFER ENDED IN AN ECC HARD ERROR BUT THERE WERE SECTORS ; TRANSFERED THAT CONTAINED GOOD DATA. SINCE THE ECC HARD ERROR COULD ; HAVE BEEN CAUSED BY A CYLINDER CROSSING, THE GOOD DATA IS SAVED ; AND THE TRANSFER IS RETRIED FROM THE POINT OF ERROR. ; 15$: CALL DBPRM0 ;RESET OFFSET RECOVERY PARAMETERS CALL DBCALC ;CALCULATE NEW PARAMETERS TST U.CNT(R5) ;ERROR ON LAST BLOCK? BNE 20$ ;IF NE NO ADD R0,U.CNT(R5) ;YES, BACKUP BYTES TO TRANSFER 20$: BITB #OFA,U.CW2+1(R5) ;OFFSET MODE ACTIVE? BNE 30$ ;IF NE YES CALL DBPRM0 ;NO, RESET OFFSET RECOVERY PARAMETERS BISB #OFA,U.CW2+1(R5) ;SET OFFSET ACTIVE 25$: MOV #117,R1 ;SET RTC FUNCTION MOV #FMT22,R0 ;SET OFFSET VALUE TO ZERO BR 50$ ; ; ; NO GOOD DATA WAS TRANSFERED - CHECK IF OFFSET SHOULD BE CHANGED ; 30$: BIT #DTE!ECH,RPER1(R2) ;DRIVE TIMING OR HARD ECC ERROR? BNE 40$ ;IF NE YES BISB #IHC,U.CW2+1(R5);SET HEADER COMPARE INHIBIT FLAG 40$: DECB RTTBL+1(R3) ;CHANGE OFFSET? BGT DBREST ;IF GT NO DECB RTTBL(R3) ;COUNT EACH OFFSET AS A RETRY ADD #2,OFFAD(R3) ;UPDATE OFFSET POINTER MOV @OFFAD(R3),R0 ;GET NEXT OFFSET VALUE BEQ 25$ ;IF EQ RETURN TO CENTERLINE MOV #115,R1 ;SET OFFSET FUNCTION MOVB #2,RTTBL+1(R3) ;SET RECOVERY RETRY COUNT BIT #2,RPDT(R2) ;IS THIS DRIVE AN RP04? BEQ 50$ ;IF EQ YES ASRB R0 ;NO, IT'S AN RP06 SO ADJUST OFFSET ... BIC #100,R0 ;... VALUE AND SIGN ACCORDINGLY 50$: MOV #TRE!11,(R2) ;CLEAR CONTROLLER AND DRIVE MOV R0,RPOF(R2) ;LOAD NEXT OFFSET VALUE BICB #IHC,U.CW2+1(R5);CLEAR HEADER COMPARE INHIBIT DBFUNC: MOVB S.ITM(R4),S.CTM(R4) ;RESET TIMEOUT COUNT MTPS #PR5 ;;;DISABLE INTERRUPTS CLR S.FRK+2(R4) ;;;RESET FORK INTERLOCK BIS #S2.ACT,S.ST2(R4) ;;;SHOW I/O IS ACTIVE MOVB R1,(R2) ;;;INITIATE OFFSET FUNCTION MTPS #0 ;ENABLE INTERRUPTS RETURN ; ; ; **-DBERL-FINISH ERROR LOGGING FOR MID-TRANSFER ERROR ; ; THIS ROUTINE IS CALLED TO FINISH OFF THE ERROR LOGGING PROCESS ; DURING MID-TRANSFER IF WE HAVE SUCCESSFULLY RECOVERED. ; ; INPUTS: ; ; R3=CONTROLLER INDEX ; DBERL: MOV R2,-(SP) ;SAVE REGISTERS MOV R1,-(SP) ; MOVB RTTBL(R3),R2 ;GET FINAL ERROR RETRY COUNT BIS #RETRY*256.,R2 ;MERGE STARTING RETRY COUNT MOV #IS.SUC&377,R0 ;RECOVERY WAS SUCCESSFUL CALL $FNERL ;FINISH ERROR LOGGING PROCESS MOV (SP)+,R1 ;RESTORE REGISTERS MOV (SP)+,R2 ; ;FALL THRU AND RESET RECOVERY PARMS. ; ; SET RECOVERY AND RETRY PARAMETERS ; DBPRM: MOV #RETRY,RTTBL(R3);SET INITIAL RETRY COUNT DBPRM0: MOVB #16.,RTTBL+1(R3) ;SET FOR 16. TIMES AT CENTERLINE DBPRM1: MOV #OFFTB,OFFAD(R3) ;SET OFFSET TABLE POINTER BICB #OFA,U.CW2+1(R5) ;RESET OFFSET ACTIVE FLAG RETURN ; ; ; **-DBCALC-CALCULATE UPDATED DISK ADDRESS ; ; THIS ROUTINE WILL CALCULATE THE NEW DISK AND BUFFER ADDRESSES ; BASED ON THE NUMBER OF BYTES ACTUALLY TRANSFERED. ; ; INPUTS: ; ; R0=BLOCKS ACTUALLY TRANSFERED. ; ; OUTPUTS: ; ; R0=UNCHANGED IF U.CNT(R5)=0 ; I.PRM+10(R1)=NEW CYLINDER ADDRESS ; I.PRM+12(R1)=NEW TRACK SECTOR ADDRESS ; DBCALC: SUB R0,U.CNT(R5) ;REDUCE BYTES REMAINING TO TRANSFER BEQ 30$ ;IF EQ NO BYTES LEFT ADD R0,U.BUF+2(R5) ;UPDATE STARTING BUFFER ADDRESS ADCB U.BUF+1(R5) ;AND THE MEMORY EXTENSION BITS BIT #FE.EXT,$FMASK ;IS 22-BIT ADDRESSING ENABLED? BEQ 5$ ;IF EQ NO MOV S.KRB(R4),R1 ;RETREIVE KRB ADDRESS BIT #KS.MBC,K.STS(R1) ;IS THIS A 22-BIT MASSSBUS DEVICE? BNE 5$ ;IF NE YES ADD K.OFF(R1),R1 ;POINT TO UMR AREA+2 ADD R0,-(R1) ;CALCULATE NEW REAL ADDRESS ADCB -(R1) ;... 5$: MOV S.PKT(R4),R1 ;RETREIVE I/O PACKET ADDRESS SWAB R0 ;CALCULATE NUMBER OF SECTORS TRANSFERED ASR R0 ; ADD I.PRM+12(R1),R0 ;UPDATE TRACK/SECTOR ADDRESS TST -(SP) ;GET A WORKING REGISTER 10$: CLR (SP) ;CLR THE WORKING REGISTER FOR LOOP CMPB U.PRM(R5),R0 ;SECTOR OVERFLOW? BHI 20$ ;IF HI NO MOVB U.PRM(R5),(SP) ;COPY SECTORS/TRACK SUB (SP),R0 ;SUBTRACT A TRACKS WORTH OF SECTORS ADD #1*256.,R0 ;ADD IN A TRACK MOV U.PRM(R5),(SP) ;GET TRACKS AND SECTORS CLRB (SP) ;ISOLATE ONLY TRACKS/CYLINDER CMP (SP),R0 ;TRACK OVERFLOW? BHI 10$ ;IF HI NO SUB (SP),R0 ;NORMALIZE TRACK ADDRESS INC I.PRM+10(R1) ;UPDATE CYLINDER ADDRESS BR 10$ ; 20$: MOV R0,I.PRM+12(R1) ;SET UPDATED TRACK/SECTOR ADDRESS TST (SP)+ ;PRUNE STACK 30$: RETURN ; ; ; **-DBVV-PROCESS VOLUME VALID FUNCTIONS ; ; HERE WE WILL PROCESS VOLUME VALID FUNCTIONS. IF THE FUNCTION IS ; RESET VOLUME VALID WWE WILL FORCE AN UNLOAD OF THE DRIVE. IF THE ; FUNCTION IS SET VOLUME VALID, WE WILL SET THE HARDWARE "VV" BIT. ; IF THE FUNCTION IS A VOLUME VALID NOP, WE WILL SIZE THE DISK BY ; PASSING THE CONTROLLER REGISTERS BACK TO THE CALLER. ; ; INPUTS: ; ; R4=ADDRESS OF THE SCB. ; R5=ADDRESS OF THE UCB ; DBVV: CALL $RQCND ;REQUEST CONTROLLER FOR DATA TRANSFER MOV #IS.SUC&377,R0 ;SET SUCCESSFUL OPERATION MOV @S.KRB(R4),R2 ;RETREIVE CSR ADDRESS MOVB U.UNIT(R5),RPCS2(R2) ;SELECT THE UNIT MOV S.PKT(R4),R1 ;RETREIVE I/O PACKET ADDRESS MOVB #111,(R2) ;CLEAR THE DRIVE BIT #NED,RPCS2(R2) ;DOES THE DRIVE EXIST? BEQ 5$ ;IF EQ YES TST I.PRM+2(R1) ;SIZE THE DISK ? BMI 4$ ;IF MINUS THEN YES CALL $DVERR ;LOG THE ERROR 4$: ;REFFERENCE LABEL MOVB #TRE/256.,RPCS1+1(R2) ;CLEAR THE CONTROLLER MOV #IE.SZE&377,R0 ;UNABLE TO SIZE UNIT BICB #US.VV,U.STS(R5);RESET VOLUME VALID JMP DBFIN2 ;EXIT 5$: TST I.PRM+2(R1) ;SIZE THE DISK? BPL 10$ ;IF PL NO CMPB RPDT(R2),#47 ; IS THIS A SHELBY DRIVE BNE 7$ ; IS NE, NOPE, CONTINUE BIT #MOL,RPDS(R2) ; DO WE HAVE MOL? BEQ 7$ ; IF EQ, NOPE, NO GEOMETRY YET ... MOVB #47,(R2) ; GET DRIVE GEOMETRY 7$: CALL $CRPAS ;PASS CONTROLLER REGISTERS TO CALLER BR 15$ ; 10$: BIT #VV$SET,I.PRM+2(R1) ;SET VOLUME VALID? BEQ 30$ ;IF EQ NO MOV RPDS(R2),R1 ;GET CONTENTS OF DRIVE STATUS REGISTER COM R1 ;TOGGLE THEM BIT #MOL!DRY,R1 ;DRIVE READY AND ONLINE? BNE 20$ ;IF NE NO CMPB RPDT(R2),#47 ; IS THIS A SHELBY? BNE 13$ ; IF NE, NOPE ... CONTINUE MOVB #47,(R2) ; ISSUE THE IDENT FUNCTION 12$: CMPB (R2),#246 ; CONTROLLER READY? BNE 12$ ; IF NE, NOPE, PAUSE A MOMENT MOV R0,-(SP) ; SAVE CURRENT STATUS CODE MOV RPCC(R2),R0 ; GET THE HIGHEST CYLINDER INC R0 ; BUMP THE HIGHEST CYLINDER MOV R0,U.PRM+2(R5) ; UPDATE THE GEOMETRY MUL #<64.*32.>,R0 ; CALCULATE THE HIGHEST LBN MOVB R0,U.CW2(R5) ; LOAD THE HIGH ORDER LBN MOV R1,U.CW3(R5) ; AND THE LOW ORDER DRIVE SIZE MOV (SP)+,R0 ; RESTORE R0 13$: MOVB #23,(R2) ;ISSUE PACK ACK TO SET VV 15$: JMP DBFIN1 ;EXIT 20$: MOV #IE.DNR&377,R0 ;DRIVE NOT READY ERROR CODE BICB #US.VV,U.STS(R5);RESET VOLUME VALID BR 15$ ;EXIT 30$: BIT #VV$UNL,I.PRM+2(R1) ;UNLOAD THE DRIVE? BEQ 15$ ;IF EQ NO BIT #PIP,RPDS(R2) ;IS THE DRIVE IN MOTION? BNE 15$ ;IF NE YES, IT'S PROBABLY UNLOADING MOVB #3,(R2) ;ISSUE UNLOAD FUNCTION BR 15$ ; ; ; **-DBCLR-CLEAR DRIVE OR SUB-SYSTEM ; **-DBCLR1-ALTERNATE ENTRY TO CLEAR DRIVE W/O INTERRUPT ENABLE ; ; ISSUE A DRIVE CLEAR FUNCTION UNLESS THE SELECTED DRIVE/CONTROLLER ; IS HUNG, THEN ISSUE SUB-SYSTEM CLEAR. ; ; INPUTS: ; ; R2=CSR ADDRESS ; R5=UCB ADDRESS ; ; OUTPUTS: ; ; SELECTED DRIVE IS CLEARED ; .ENABL LSB DBCLR: TSTB (R2) ;IS THE CONTROLLER READY? BPL 10$ ;IF PL NO BIT #1,(R2) ;IS GO BIT SET? BNE 10$ ;IF NE YES MOVB #111,(R2) ;NO, ISSUE DRIVE CLEAR RETURN ;AND EXIT DBCLR1: TSTB (R2) ;IS THE CONTROLLER READY? BPL 10$ ;IF PL NO BIT #1,(R2) ;IS GO BIT SET? BNE 10$ ;IF NE YES MOVB #11,(R2) ;NO, ISSUE DRIVE CLEAR RETURN ;AND EXIT ; ; NOTE: ; ; THE FOLLOWING INSTRUCTION WILL CAUSE ALL I/O ON OTHER UNITS TO ; ABORT. THIS IS OK BECAUSE THE TIMEOUT FACILITY SHOULD CATCH THEM. ; 10$: BIS #40,RPCS2(R2) ;ISSUE SUB-SYSTEM CLEAR MOVB U.UNIT(R5),RPCS2(R2) ;RE-SELECT THE DRIVE RETURN ;AND EXIT .DSABL LSB ;+ ; **-DBCHK-VALIDATE AND CONVERT THE LBN ; ; THIS ROUTINE IS CALLED FROM $DRQRQ TO DO LBN PROCESSING ; FOR DEVICES WHICH SUPPORT QUEUE OPTIMIZATION. IF BLKC2 ; DETECTS AN ERROR IT WILL RETURN TO THE CORRECT PLACE IN ; $DRQRQ AFTER CALLING $IOALT. ; ; INPUTS: ; ; R1=I/O PACKET ADDRESS ; R5=UCB ADDRESS ; ; OUTPUTS: ; ; IF THE CHECKS SUCCEEDS, THEN THE LBN IN THE PACKET ; IS REPLACED BY THE CYLINDER/TRACK/SECTOR. R1 IS PRESERVED. ; ; IF THE CHECKS FAILS, THEN $IOALT IS ENTERED WITH A FINAL ; STATUS OF IE.BLK AND A RETURN TO THE CORRECT PLACE IN ; $DRQRQ IS EXECUTED. ; ; ; NOTE: ALL FUNCTIONS PUT INTO THE DRIVER QUEUE ARRIVE HERE. ; THESE INCLUDE IO.ATT, IO.DET, AND ACP FUNCTIONS. ;- DBCHK: MOV I.FCN(R1),-(SP) ;PUT THE FUNCTION ONTO THE STACK CMPB #IO.ATT/256.,1(SP) ;IS IT ATTACH BEQ 15$ ;IF EQ YES - LEAVE IT ALONE CMPB #IO.DET/256.,1(SP) ;IS IT DETACH BEQ 15$ ;IF EQ YES - LEAVE IT ALONE BIC #7,(SP) ;CLEAR THE SUBFUNCTION BITS CMP #IO.STC,(SP) ;IS IT SET CHARACTERISTICS? BEQ 15$ ;IF EQ YES - LEAVE IT ALONE TST (SP)+ ;CLEAN THE STACK CALL $BLKC2 ;CHECK LOGICAL BLOCK NUMBER CALL $CVLBN ;CONVERT LOGICAL BLOCK NUMBER MOV R2,I.PRM+10(R3) ;SAVE DESIRED CYLINDER ADDRESS SWAB R1 ;SWAP TRACK TO HIGH BYTE BIS R1,R0 ;MERGE TRACK WITH SECTOR MOV R0,I.PRM+12(R3) ;SAVE DESIRED TRACK AND SECTOR ADDRESS MOV R3,R1 ;RESTORE THE PACKET ADDRESS 10$: RETURN ;EXIT 15$: TST (SP)+ ;CLEAN THE STACK BR 10$ ;AND EXIT .END